require 'gserver'

class Netfluxd < GServer

  TIME_SLICE = 5

  def initialize(port = nil, *args)
		@log = Logger.new(Conf.Logging ? Conf::LOG_PATH : nil)
		@log.debug('initialize [')

    super(port, *args)

    @status = 'initializing'
    @checkQueueTimeout = 0
    @checkQueue = 0
    @doReconfig = false
    @port = port.to_s
    @nfClient = nil

    @log.debug('initialize ]')
  end

  def config
    @log.debug('config [')

    @reconfig = false

    # Check configuration
    isValid, msg = Conf.is_valid
    @log.debug("msg = #{msg.inspect}")

    if not isValid
      @log.error("Configuration error:\n" + msg.join("\n"))
      @status = 'bad configuration'
      @log.debug('config ]')
      return
    end

    @pollInterval = Conf.PollInterval.to_i * 60 / TIME_SLICE

    queue

    @status = 'OK'

    @log.debug('config ]')
  end

  def queue
    @checkQueue = 0
  end

  def serve(io)
    io.puts('Welcome to Netfluxd. Type "help" for options.')

    loop do
      io.print('> ')

      if IO.select([io], nil, nil, nil)
        line = io.gets

        if line =~ /help/
          io.puts(
            "help     - this text\n" +
            "status   - status\n" +
            "queue    - check Netflix queue\n" +
            "config   - re-read configuration\n" +
            "quit     - quit\n" +
            "shutdown - shutdown\n"
          )
        elsif line =~ /status/
          io.puts(@status)

        elsif line =~ /queue/
          io.puts('Scheduling queue check.')
          queue

        elsif line =~ /config/
          io.puts('Scheduling reconfiguration.')
          @reconfig = true

        elsif line =~ /quit/
          io.puts('Goodbye...')
          break

        elsif line =~ /shutdown/
          io.puts('Scheduling shutdown.')
          @nfClient.cancel if @nfClient
          self.stop

        else
          io.puts("Unknown command \"#{line.chomp}\".")

        end
      end
    end
  end

  def run
    @log.debug('start')

    config

    start

    @log.info("Netfluxd started, listening on port #{@port}")

    begin
      video = nil

      # Check for incomplete download
      if @status == 'OK'
        video = Video.find_by_status_id(VideoStatus::DOWNLOADING)

        if video
          @log.info("Resuming download \"#{video.title}\"")
        else
          # Scrape queue for next movie
          @log.info('Checking queue...')
  
          @nfClient = NetflixClient.new(@log)
          @log.debug('nfClient created')
  
          q = @nfClient.get_queue
          @log.debug("nfClient queue = #{q.inspect}")
  
          q.each {|movie|
            # Lookup movie in local db
            video = Video.find_or_initialize_by_nf_id(movie['movieId'])
  
            if video.new_record?
              bitrate = case Conf.Bitrate
                when 'highest' then nil
                when 'lowest' then 0
                when 'custom' then Conf.BitrateCustom
              end

              dlUrl = @nfClient.get_download_url(movie['link'], bitrate)

              video.remote_url    = movie['remote']
              video.title         = movie['title']
              video.file_name     = File.join(Conf.Path, video.title.gsub(%r{["/\\*?<>|:]}, '_') + '.wmv')
              video.download_url  = dlUrl
              video.save

              @log.debug("Video id #{video.id} created")
              @log.info("Downloading movie \"#{video.title}\"")
              break
            end
          }
        end
      end

      if video
        # Download
        @nfClient ||= NetflixClient.new(@log)

        result = @nfClient.download(video.download_url, video.file_name)

        if result[:video]
          video.status_id = result[:video]
          video.save
        end

        @status = result[:server] if result[:server]

        # TODO If configured to remove from queue, do so

      else
        # If nothing to download, sleep
        if @status != 'OK'
          @log.warn('Configuration issue; going to sleep')
        else
          @status = 'sleeping'
          @log.info('No new videos found; going to sleep')
        end

        @checkQueue = @pollInterval

        begin
          sleep(TIME_SLICE)

          # Decrement poll interval
          @checkQueue -= 1 if @checkQueue

          if @reconfig
            @log.info('Reconfiguring...')
            config
          end
        end until stopped? or @checkQueue == 0

        if @checkQueue == 0 and @status == 'sleeping'
          @status = 'OK'
        end
      end
    end until stopped?

    @log.info('Netfluxd stopped')
  end

end

Netfluxd.new(Conf.Port).run
